package nl.hanze.shoestring.logic;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import nl.hanze.shoestring.dao.DAOFacade;
import nl.hanze.shoestring.dao.impl.DAOFacadeImpl;
import nl.hanze.shoestring.domain.*;

/**
 *
 * @author alex / henk
 */
public class Rules {

    DAOFacade facade;

    public Rules() {
        facade = new DAOFacadeImpl();
    }

    /**
     * P001 Checkt of de gids een geldige bankrekening heeft
     *
     * @param mdw Medemerker
     * @return
     */
    public static boolean checkGidsBankAccount(Medewerker mdw) {
        if (mdw.getGids()) {
            return checkBankAccount(mdw.getPersoon());
        } else {
            return false;
        }
    }

    /**
     * Checkt of een persoon een geldig bankrekeningnummer heeft
     *
     * @param persoon
     * @return
     */
    public static boolean checkBankAccount(Persoon persoon) {
        String account = String.valueOf(persoon.getRekeningnummer());
        return checkBankAccount(account);
    }

    /**
     * Checkt of een bankrekeningnummer geldig is
     *
     * @param account
     * @return
     */
    public static boolean checkBankAccount(String account) {
        //Check of bankrekening uit cijfers bestaat
        for (char c : account.toCharArray()) {
            if (!Character.isDigit(c)) {
                return false;
            }
        }
        //Bankrekening bestaat uit cijfers. Check lengte.
        return account.length() == 9;
    }

    /**
     * P003 Checkt of de lengte van de reis in de planning overeenkomt met de
     * lengte in de reis
     *
     * @param planning
     * @return
     */
    public static boolean checkReisLength(Planning planning) {
        //+1 omdat begin- en einddag horen ook bij de reis horen.
        int numDays = (int) (planning.getDatumTot().getTime() - planning.getDatumVan().getTime())
                / (24 * 60 * 60 * 1000) + 1;
        return planning.getReisId().getDuur() == numDays;
    }

    /**
     * P005 Checkt of de start van een te plannen reis in de toekomst ligt
     *
     * @param planning
     * @return
     */
    public static boolean checkReisStartDate(Planning planning) {
        Calendar cal = new GregorianCalendar();
        Date today = cal.getTime();
        return planning.getDatumVan().compareTo(today) > 0;
    }

    /**
     * P002 Gidsen kunnen niet ingepland worden als ze al een reis begeleiden
     * Methode wanneer een bestaande planning wordt gewijzigd
     *
     * @param medewerker
     * @param planning
     * @return
     */
    public static boolean checkGidsBeschikbaar(Medewerker medewerker, Planning planning) {
        return checkGidsBeschikbaar(medewerker, planning.getDatumVan(), planning.getDatumTot());
    }

    /**
     * P002 Gidsen kunnen niet ingepland worden als ze al een reis begeleiden
     * Methode indien de Planning nog niet bestaat (nieuwe planning)
     *
     * @param medewerker
     * @param planning
     * @return
     */
    public static boolean checkGidsBeschikbaar(Medewerker medewerker, Date DatumVan, Date DatumTot) {
        List<Planning> planningList = medewerker.getPlanningList();
        //Retour false als medewerker geen gids is
        if (!medewerker.getGids()) {
            return false;
        }
        //Retourneer true als gids nog niet is ingepland        
        if (planningList.isEmpty()) {
            return true;
        }
        //Als planningen overlappen return false
        for (Planning p : planningList) {
            if ((DatumVan.compareTo(p.getDatumVan()) >= 0 && DatumVan.compareTo(p.getDatumTot()) <= 0)
                    || (DatumTot.compareTo(p.getDatumVan()) >= 0 && DatumTot.compareTo(p.getDatumTot()) <= 0)
                    || DatumVan.compareTo(p.getDatumVan()) <= 0 && DatumTot.compareTo(p.getDatumTot()) >= 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * P006-1 Checkt of deelnemer niet gelijktijdig gids is. Nodig als deelnemer
     * aan een planning wordt toegevoegd.
     *
     * @param deelnemer
     * @param planning
     * @return
     */
    public static boolean checkGidsAlsDeelnemer(Deelnemer deelnemer, Planning planning) {
        //Als deelnemer geen medewerker is of wel medewerker maar geen gids return true
        if (deelnemer.getKlantId().getPersoon().getMedewerker() == null || !deelnemer.getKlantId().getPersoon().getMedewerker().getGids()) {
            return true;
        }

        //Deelnemer is gids. Check of deze gids ingepland is als gids voor deze planning.
        return deelnemer.getKlantId().getPersoon().getMedewerker() == planning.getGidsId() ? false : true;
    }

    /**
     * P006-2 Checkt of gids niet gelijktijdig deelnemer is. Nodis als een gids
     * aan een planning wordt toegevoegd.
     *
     * @param deelnemer
     * @param planning
     * @return
     */
    public static boolean checkGidsAlsDeelnemer(Medewerker medewerker, Planning planning) {
        //Als medewerker geen klantaccount heeft kan deze niet gelijktijdig aan een reis deelnemen
        if (medewerker.getPersoon().getKlant() == null) {
            return true;
        }

        //Haal alle deelnemers op bij deze planning en vergelijk met huidige planning
        for (Reservering res : planning.getReserveringList()) {
            for (Deelnemer deelnemer : res.getDeelnemerList()) {
                if (deelnemer.getKlantId().getPersoon().getMedewerker() == medewerker) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * P004 Reis mag niet meer aangepast worden als er een planning is
     *
     * @param reis De aan te passen reis
     * @return true als reis nog niet ingepland is.
     */
    public static boolean checkChangeDuurReis(Reis reis) {
        return reis.getPlanningList().isEmpty();
    }

    /**
     * C003 Kortingen zijn een veelvoud van 2.5
     *
     * @param kortingpercentage
     * @return true als veelvoud van 2,5
     */
    public static boolean checkKortingPercentage(String korting) {
        if (korting == null || korting.isEmpty()) {
            return false;
        }
        float value = Utils.getFloatValueOrNull(korting);
        return value % 2.5 == 0;
    }

    /**
     * C003 Kortingen zijn een veelvoud van 2.5
     *
     * @param kortingpercentage
     * @return true als veelvoud van 2,5
     */
    public static boolean checkKortingPercentage(Groepskorting groepskorting) {
        String korting = String.valueOf(groepskorting.getKorting());
        return checkKortingPercentage(korting);
    }

    /**
     * B002 + B003 Postcode validatie
     *
     * @param postcode NL
     * @return true bij juist patroon
     */
    public static boolean checkPostCode(String pc) {
        if (pc.isEmpty()) {
            return false;
        }
        String regexp = "^[1-9][0-9]{3}[A-Z]{2}$";
        return pc.matches(regexp);
    }

    /**
     * W005 Checkt of reisdatum in de toekomst ligt zodat er geannuleerd kan
     * worden
     *
     * @param reservering
     * @return
     */
    public static boolean checkReisAnnuleringDate(Reservering res) {
        Calendar cal = new GregorianCalendar();
        Date today = cal.getTime();
        return res.getPlanningId().getDatumVan().compareTo(today) > 0;
    }

    /**
     * W006 Check of de annuleringsdatum na de boekingsdatum ligt
     *
     * @param reservering
     * @param datum annulering
     * @return true/false
     */
    public static boolean checkReisAnnuleringDatumNaBoekingsDatum(Reservering res, Date dateAnullering) {
        return res.getDatumBoeking().compareTo(dateAnullering) < 0;
    }
    
    /**
     * B008-A Check of het maximum aantal deelnemers niet wordt overschreden
     *
     * @param reservering
     * @param datum annulering
     * @return true/false
     */
    public static boolean checkMaxAantalDeelnemers(Reservering res) {
        List<Reservering> resveringen = res.getPlanningId().getReserveringList();
        int aantalDeelnemers = 0;
        
        for (Reservering reservering : resveringen) {
            if(reservering.getDatumAnnulering() == null){
                aantalDeelnemers += reservering.getDeelnemerList().size();
            }
        }
        
        return aantalDeelnemers >= getMaxAantalDeelnemersReservering(res);
    }
    
    /**
     * B008-B Get het maximum aantal deelnemers voor Reservering
     *        ivm overschrijden max aantal   
     * @param reservering
     * @return maximumaantal
     */
    public static int getMaxAantalDeelnemersReservering(Reservering res) {
        return res.getPlanningId().getAantalMaximum();
    }

    /**
     * W007 Check of het reservering is geannuleerd
     *
     * @param reservering
     * @param datum annulering
     * @return true/false
     */
    public static boolean isReserveringGeannuleerd(Reservering res) {
        return res.getDatumAnnulering()!=null;
    }

    /**
     * B006/B007 Check of toe te voegen Klant niet toevallig al Deelnemer is
     *           Indien true wordt deze deelnemr geretourneerd 
     *
     * @param klant
     * @param reservering
     * @return Deelnemer 
     */
    public static Deelnemer getDeelnemerFromSelectedKlant(Klant klantObj, Reservering resObj) {
        List<Deelnemer> deelnemers = resObj.getDeelnemerList();
        for (Deelnemer d : deelnemers) {
            // System.out.println("d=" + d.toString());
            if(d.getKlantId().getId()==klantObj.getId()) {
                return d;
            }
        }
        return null;
    }

    /**
     * B005  Check maximum leeftijd Deelnemerbij toevoegen aan Reservering
     *        
     * @param reservering
     * @return maximumaantal
     */
    public static boolean checkMaximumLeeftijdOverschreden(Reservering res, Klant klantObj) {
        Calendar now = Calendar.getInstance();
        Calendar dob = Calendar.getInstance();
        dob.setTime(klantObj.getPersoon().getGeboortedatum());
        int lft = now.get(Calendar.YEAR) - dob.get(Calendar.YEAR);
        return lft > res.getPlanningId().getMaximumLeeftijd();
    }
    
    /**
     *  Is String empty
     * @param s
     * @return 
     */
    public static boolean isEmpty(String s) {
        if (s == null) {
            return true;
        }
        if (s.length() == 0) {
            return true;
        }
        return false;
    }

    /**
     *  Is string Numeriek
     * @param s
     * @return 
     */
    public static boolean isNumeric(String s) {
        for (char c : s.toCharArray()) {
            if (!Character.isDigit(c)) {
                return false;
            }
        }
        return true;
    }
}
